home *** CD-ROM | disk | FTP | other *** search
Wrap
/************************************************************************/ /* */ /* XMODEM.DLP */ /* */ /* This is a sample (DLP) DLL to implement the XMODEM protocol */ /* */ /* Four calls are made to the (DLP) by PW.EXE */ /* GET_DLL_CAPS( LPSTR ) */ /* ADVANCED_DLL( PROTOSET FAR *, MAIN FAR *, HWND, LPSTR ) */ /* STARTDLL_XFER( PROTOSET FAR *, MAIN FAR *, HWND, LPSTR, int, int ) */ /* DLL_XFER( PROTOSET FAR *, MAIN FAR *, HWND, LPSTR, int ) */ /* */ /* PROTOSET is a struct of PW.EXE variables which the protocol can */ /* use. It also contains callback fuctions for all the */ /* communication functions necessary to implement a */ /* protocol. A large global buffer is already allocated */ /* (10240 bytes) and pd->bigptr is a locked pointer to this */ /* memory. 66 extra bytes are contained in the struct to */ /* be cast and used by the (DLP) as required. Reference */ /* XMODEM.H. The (DLP) should use this area for any global */ /* variables it requires, thus supporting mulitple instances */ /* use of the protocol. */ /* */ /* MAINSET is a struct of PW.EXE variables of a more general nature */ /* which the protocol can use. Reference XMODEM.H. */ /* */ /* ADVANCED_DLL, STARTDLL_XFER, & DLL_XFER are all passed a LPSTR to */ /* 3 bytes of exta data which is intended to be used for */ /* advanced settings. */ /* */ /* Note: To allow aspect to determine sucess or failure of the */ /* protocol *(pd->aspfxfer) should be set to equal to */ /* ASP_PROT_FAIL on entry and set to ASP_PROT_SUCCESS on */ /* termination if successful. */ /* */ /************************************************************************/ /************************************************************************/ /* */ /* This sample is provided as a service to you. DATASTORM does not in */ /* any way warrant the source code, nor do we commit to any support on */ /* this sample file. */ /* */ /************************************************************************/ #define _WINDOWS #define _WINDLL #include <windows.h> #include <string.h> #include <io.h> #include <dos.h> #include "xmodem.h" //▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //▓▓ //▓▓ global variables used by xmodem.dlp //▓▓ //▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ char szBuffer[128]; PROTOSET FAR *pd; MAIN FAR *mn; HWND hWnd; HANDLE hInst; ADVANCEDSET adv; //▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //▓▓ //▓▓ 1. DLL entry and exit routines //▓▓ //▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //-------------------------------------------------------------------------- // // LibMain() - DLL entry function // //-------------------------------------------------------------------------- BOOL FAR PASCAL LibMain(hInstance, wDataSeg, cbHeapSize, lpszCmdLine) HANDLE hInstance; WORD wDataSeg; WORD cbHeapSize; LPSTR lpszCmdLine; { hInst = hInstance; // save instance handle for dialog box and resources if(cbHeapSize !=0 ) UnlockData(0); return(1); } //-------------------------------------------------------------------------- // // WEP() - DLL termination function // // Notes: 1. WEP may not be called when the DLL closes and therefore // cannot be counted on to perform termination tasks. // //-------------------------------------------------------------------------- void FAR PASCAL WEP(nParamater) int nParamater; { return; } /**********************************************************************/ /* */ /* GET_DLL_CAPS */ /* */ /* This procedure is called by PW.EXE when a new (DLP) file is */ /* found in the PW.EXE directory. The (DLP) is to return the */ /* bitflags of its capablities. */ /* */ /* DLL_CAP_SHOWXFER-requests PW.EXE to show its normal xfer dlg box */ /* DLL_CAP_MULTISEND-(DLP) is capable of sending multiple files */ /* DLL_CAP_AUTODOWNLOAD-(DLP) is capable of autodowloading files */ /* DLL_CAP_PWOPENFILE-requests PW.EXE to open the inital file */ /* DLL_CAP_RCVNEEDNAME-PW.EXE is to prompt user for a rcv file name */ /* DLL_CAP_ADVANCED-(DLP) has advanced dialog box for user setup */ /* */ /* If (DLP) return DLL_CAP_AUTODOWNLOAD, then the auto detect string */ /* (null terminated, 11 char max.) should be copied to lptr */ /* passed into the function. */ /* */ /**********************************************************************/ WORD FAR PASCAL GET_DLL_CAPS( lptr ) LPSTR lptr; { WORD i = 0; return( i | DLL_CAP_ADVANCED | DLL_CAP_RCVNEEDNAME ); // lstrcpy( lptr,"0x1b0x1b"); // if autodownload capable // return( i | DLL_CAP_AUTODOWNLOAD | DLL_CAP_ADVANCED | DLL_CAP_RCVNEEDNAME ); } /**********************************************************************/ /* */ /* ADVANCED_DLL */ /* */ /* This procedure is called by PW.EXE when the (DLP) has return the */ /* DLL_CAP_ADVANCED capablity flag and the user has selected the */ /* advanced menu (or dblclicked on the protocol button). */ /* it is intened to allow the (DLP) to provide a Dialog box for */ /* advanced options. */ /* */ /* Note: This is a dummy routine, for example only */ /* */ /**********************************************************************/ void FAR PASCAL ADVANCED_DLL( inpd, inmn, hwnd, extra ) PROTOSET FAR *inpd; MAIN FAR *inmn; HWND hwnd; // handle to the parent window, for dialog box LPSTR extra; // 3 Bytes of information for advanced setup { FARPROC lpproc; adv = *(ADVANCEDSET FAR *)extra; lpproc = MakeProcInstance(SetupDlgProc, hInst ); DialogBox(hInst,"SETUP",hwnd,lpproc ); FreeProcInstance( lpproc ); *(ADVANCEDSET FAR *)extra = adv; } /**********************************************************************/ /* */ /* STARTDLL_XFER */ /* */ /* Allows (DLP) to initialize variables and start the actual xfer. */ /* send = TRUE if sendin a file, FALSE receiving a file */ /* from_auto = TRUE if called from auto detect sequence */ /**********************************************************************/ int FAR PASCAL STARTDLL_XFER( inpd, inmn, hwnd, extra, send, from_auto) PROTOSET FAR *inpd; MAIN FAR *inmn; HWND hwnd; LPSTR extra; int send; int from_auto; { pd = inpd; mn = inmn; // if(from_auto) // if auto detect the initialize // { // lstrcpy( pd->szTempDir,"d:\\pw"); // lstrcpy( pd->szTempName,"temp.gif"); // } if(!FileRxTX(send, pd->szTempName )) { (*pd->EndXfer)(); return(FALSE); } // Init. global varables --------------------------------------------------- pd->rec_len = 128; pd->xcount = 132; pd->datalen = 0; pd->Aborting = 0; pd->no_char_wait = 1000; pd->retries = 3; pd->runcnt = 0; pd->xcount = 0; // ------------------------------------------------------------------------- if(pd->bdiag) // if requested show xfer box, ASPECT can request this to be FALSE { (*pd->ShowXferBox)(send); // Call PW.EXE function to show xfer box SetWindowText( pd->hDlg1,"DLL [XModem]"); } if(send) { pd->pcstate = IDX_WAITACK; // set state to show we are sending pd->bbegin = 1; pd->end_record = 255; } else // receiving { pd->pcstate = IDX_RXING; // set state to show we are receiving pd->bbegin = 2; pd->rec_no = 1; // initialize record count pd->end_record = 0; pd->xwaittime = GetTickCount()+10000; // set timout to 10 seconds (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x15",(int)1); // start with NACK } return(TRUE); } /**********************************************************************/ /* */ /* DLL_XFER */ /* */ /* Called every timer tick (~55msecs) */ /**********************************************************************/ int FAR PASCAL DLL_XFER(inpd, inmn, hwnd, extra, send) PROTOSET FAR *inpd; MAIN FAR *inmn; HWND hwnd; LPSTR extra; int send; { pd = inpd; mn = inmn; switch(pd->pcstate) // switch on xfer state { case IDX_RXING: RXING(); break; case IDX_NOCHAR: NOCHAR(); break; case IDX_WAITACK: WAITACK(); break; } return(TRUE); } //▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓ //█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█ //▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓ //█▓█▓ ▓█▓█ //▓█▓█ █▓█▓ //█▓█▓ L O C A L R O U T I N E S ▓█▓█ //▓█▓█ █▓█▓ //█▓█▓ ▓█▓█ //▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓ //█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█ //▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓ BOOL FAR PASCAL SetupDlgProc( hDlg, message, wParam, lParam ) HWND hDlg; WORD message; WORD wParam; LONG lParam; { switch (message) { case WM_INITDIALOG: CheckDlgButton( hDlg, 10, (adv.fRcvFileSelect?0:1)); CheckDlgButton( hDlg, 11, (adv.fSendFileSelect?0:1)); CheckRadioButton( hDlg, 20, 21, 20+(adv.fChecksum?1:0)); CheckRadioButton( hDlg, 30, 31, 30+(adv.fRecLength128?1:0)); return(TRUE); case WM_COMMAND: // the only command is OK if(wParam != 1) return(FALSE); adv.fRcvFileSelect = IsDlgButtonChecked( hDlg,10)?0:1; adv.fSendFileSelect = IsDlgButtonChecked( hDlg,11)?0:1; adv.fChecksum = IsDlgButtonChecked( hDlg,21)?1:0; adv.fRecLength128 = IsDlgButtonChecked( hDlg,31)?1:0; EndDialog( hDlg, TRUE ); break; default: return( FALSE ); } return( TRUE ); } void RXING() { LPSTR lptr; int i,j; if(pd->bCancel) // set when user presses cancel on the xfer box { if(pd->hDlg1) // if xfer box is diplayed, show "Aborting by user" LastError(4); End_It(17); return; // we have cancel pressed so terminate */ } if( GetTickCount() > pd->xwaittime) // we timed-out? { if(pd->hDlg1) LastError(1); if(pd->bbegin==2) // we have not started xfer yet, if retries is OK send another NACK { if(--pd->retries == 0) { End_It(14); return; } (*pd->WriteCommW) ( (HANDLE)mn->hCid, (LPSTR)"\x15", (int)1); pd->xwaittime = GetTickCount()+10000; return; } else if(pd->bbegin == 99) // special case, we timed out after sending EOF, and not received NACK { if(_lwrite( pd->hCommFile, pd->bigbuff, (WORD)(pd->bigptr-pd->bigbuff)) != (WORD)(pd->bigptr-pd->bigbuff)) StatusLine(IDS_LASTERROR+19,NULL); // Show error writing file else StatusLine(IDS_LASTERROR+14,pd->szRcvFile); // Completed Xfer (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x06",(int)1); /* this is ack sent after we sent a nack but got no responce and protocol != batch stuff */ *pd->aspfxfer = ASP_PROT_SUCCESS; (*pd->EndXfer)(); // leave xfer return; } else { pd->xwaittime = GetTickCount()+20000; if(pd->bbegin > 2) pd->bbegin +=1; else pd->bbegin = 3; if(pd->bbegin == 5) (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x15",(int)1); return; } } switch(GetXRecord()) { case IDX_RXING: break; case IDX_ACK: if(((BYTE)pd->rec_no == (BYTE)*(pd->cbuff+1)) && ((BYTE)(*(pd->cbuff+2)+pd->rec_no) == 255)) { lptr = pd->cbuff; lptr += 3; (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x06",(int)1); //▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ // If we're not in a gif state and we want to be //▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ if(!mn->gifstate && pd->should_gif) { //▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ // If this is the first block //▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ if (pd->runcnt == 0) { AnsiLower((LPSTR)pd->szRcvFile); if(_fstrstr(pd->szRcvFile,".gif")) (*pd->startgif)(); } } for(i=0;i<pd->rec_len;i++) { if(mn->gifstate) { j = (*pd->FeedDisplay)((BYTE)*lptr); if(!j) { StatusLine(IDS_LASTERROR+36,pd->szRcvFile); if (!pd->hDlg1 && pd->bdiag) { (*pd->ShowXferBox)(0); // show xfer box for recieve SetWindowText( pd->hDlg1,"DLL [XModem]"); SetDlgItemText(pd->hDlg1, ID_FILENAME,AnsiLower(pd->szRcvFile)); } } } *pd->bigptr++ = *lptr++; } //▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ // If we're not doing gifs and we // don't have a status box up //▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ if (!mn->gifstate) { if (!pd->hDlg1 && pd->bdiag) { (*pd->ShowXferBox)(0); // show xfer box for recieve SetWindowText( pd->hDlg1,"DLL [XModem]"); SetDlgItemText(pd->hDlg1, ID_FILENAME,AnsiLower(pd->szRcvFile)); } } if(pd->bigptr == (pd->bigbuff+10240)) { if(_lwrite( pd->hCommFile, pd->bigbuff, 10240 ) != 10240) { End_It(20); return; } pd->bigptr = pd->bigbuff; } pd->rec_no +=1; pd->rec_no &= 0xff; pd->runcnt += pd->rec_len; if(pd->hDlg1) { wsprintf(szBuffer,"%lu",pd->runcnt); SetDlgItemText(pd->hDlg1,ID_BLKNO, szBuffer); LastError(0); } pd->pcstate = IDX_RXING; } /* bad record routine */ else if(((BYTE)(pd->rec_no-1) == (BYTE)*(pd->cbuff+1)) && ( (BYTE)(*(pd->cbuff+2)+pd->rec_no-1) == 255)) { (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x06",(int)1); if(pd->hDlg1) { SetDlgItemInt( pd->hDlg1,ID_ERR,++pd->nackcount,0); if(pd->nackcount > 20) pd->bCancel = 2; LastError(7); } pd->pcstate = IDX_RXING; } else if(pd->rec_no == 0) End_It(24); else End_It(19); pd->xwaittime = GetTickCount()+20000; pd->xcount = 0; return; case IDX_NOCHAR: if(pd->bCancel) { if(pd->hDlg1) LastError(4); End_It(17); return; /* we have cancel pressed so terminate */ } pd->xcount = pd->bbegin = 0; pd->xwaittime = GetTickCount() + pd->no_char_wait; return; case IDX_EOT: if(pd->bbegin != 99) // first send a nack to make sure it was a valid EOT*/ { (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x15",(int)1); pd->bbegin = 99; pd->pcstate = IDX_RXING; pd->xwaittime = GetTickCount()+2000; // just wait 2 seconds for this to happen */ } else { if(_lwrite( pd->hCommFile, pd->bigbuff, (WORD)(pd->bigptr-pd->bigbuff)) != (WORD)(pd->bigptr-pd->bigbuff)) StatusLine(IDS_LASTERROR+19,NULL); /* Show error writing file */ else StatusLine(IDS_LASTERROR+14,pd->szRcvFile); /* Completed Xfer */ (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x06",(int)1); *pd->aspfxfer = ASP_PROT_SUCCESS; (*pd->EndXfer)(); } return; default: return; } } void WAITACK() { if(pd->bCancel && !pd->Aborting) // set so user knows we are pd->Aborting { pd->Aborting = TRUE; *pd->aspfxfer = ASP_PROT_FAIL; // pointer to aspect file xfer flag if(pd->hDlg1) LastError(4); if(pd->bbegin==1) End_It(17); return; /* we have cancel pressed so terminate */ } if( GetTickCount() > pd->xwaittime ) { if(pd->rec_no != pd->end_record) // if they are equal we have good Xfer { End_It(1); return; } (*pd->EndXfer)(); return; } switch(WaitingForAck()) { case IDX_TERMINATE: End_It(13); return; case IDX_WAITACK: return; case IDX_ACK: if(pd->bCancel) { End_It(17); return; } ymodem_tx(); pd->xwaittime = GetTickCount()+20000; } } void NOCHAR() { if(pd->bCancel) { *pd->aspfxfer = ASP_PROT_FAIL; // pointer to aspect file xfer flag if(pd->hDlg1) LastError(4); } if(!MoreCharacters()) pd->xwaittime = GetTickCount() + pd->no_char_wait; else if(GetTickCount() > pd->no_char_wait) { (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x15",(int)1); pd->xwaittime = GetTickCount()+20000; // 20 seconds pd->pcstate = IDX_RXING; } } // Place a message on PW.EXE statusline void StatusLine(index,lptr) WORD index; LPSTR lptr; { char line[128]; LoadString( hInst,index,line,80); // get resource string if(lptr) lstrcat(line,lptr); (*pd->StatusLineDirect) ( (LPSTR)line); // call statusline function in PW.EXE } void LastError(i) int i; { char line[21]; if(pd->hDlg1) { if(i) LoadString( hInst, IDS_LASTERROR+i-1, (LPSTR)line, 20); else line[0] = 0; SetDlgItemText( pd->hDlg1,ID_UARTERR,(LPSTR)line); } } void End_It(i) int i; { (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x18\x18\x18\x18\x18\x18\x18\x18\x08\x08\x08\x08\x08\x08\x08\x08",(int)16); StatusLine(IDS_LASTERROR+i-1,NULL); *pd->aspfxfer = ASP_PROT_FAIL; // pointer to aspect file xfer flag (*pd->EndXfer)(); } void StartXRecord(dlen, data) int dlen; LPSTR data; { LPSTR s; int i,crc; s=pd->cbuff; pd->datalen = dlen; pd->rec_no +=1; *s++ = 1; *s++ = (BYTE)(pd->rec_no); *s++ = (BYTE)(255-pd->rec_no); (*pd->WriteCommW)( (HANDLE)mn->hCid,(LPSTR)(s-3),(int)3); crc = 0; for(i=0; i<pd->rec_len;i++) { *s=*data; crc += *data++; (*pd->WriteCommW)( (HANDLE)mn->hCid,(LPSTR)s++, (int)1); } *s = LOBYTE(crc); (*pd->WriteCommW)( (HANDLE)mn->hCid,(LPSTR)s,(int)1); pd->pcstate=IDX_WAITACK; } int WaitingForAck() { char recvchar[1]; if( (*pd->GetCommErrorW) ((HANDLE)mn->hCid)) { while( (*pd->GetCommErrorW) ((HANDLE)mn->hCid)); (*pd->FlushCommW) ( (HANDLE)mn->hCid, (int)1); /* flush recieve que */ if(pd->hDlg1) { SetDlgItemInt( pd->hDlg1,ID_ERR,++pd->nackcount,0); if(pd->nackcount > 20) pd->bCancel = 2; LastError(8); } } else if(mn->comstat.cbInQue >= 1) { (*pd->ReadCommW) ( (HANDLE)mn->hCid,(LPSTR)recvchar,(int)1); if(*recvchar == ACK) pd->pcstate = IDX_ACK; else if((*recvchar == NAK) && !pd->bbegin) { if(pd->bCancel) return(pd->pcstate = IDX_ACK); (*pd->FlushCommW) ( (HANDLE)mn->hCid,(int)0); (*pd->WriteCommW) ( (HANDLE)mn->hCid, (LPSTR)pd->cbuff, (int)pd->xcount); if(pd->hDlg1) { SetDlgItemInt( pd->hDlg1,ID_ERR,++pd->nackcount,0); if(pd->nackcount > 20) pd->bCancel = 2; LastError(6); } } else if(*recvchar == CANCEL) { (*pd->FlushCommW) ( (HANDLE)mn->hCid,(int)0); pd->pcstate = IDX_TERMINATE; } else if((*recvchar == NAK) && (pd->bbegin == 1)) { if(pd->bCancel) return(pd->pcstate = IDX_ACK); else pd->xcount = 132; pd->pcstate = IDX_ACK; pd->bbegin = 0; } else (*pd->FlushCommW) ( (HANDLE)mn->hCid,(int)1); } return(pd->pcstate); } int GetXRecord() { short i; int j,k,l; if(pd->rcnt>(3*pd->xcount)/4 && pd->xcount) k=4; else k=1; for(j=0;j<k;j++) { l = (*pd->GetCommErrorW) ((HANDLE)mn->hCid); if(l) { while((*pd->GetCommErrorW) ((HANDLE)mn->hCid)); i = 8; error_state: if(pd->hDlg1) { SetDlgItemInt( pd->hDlg1,ID_ERR,++pd->nackcount,0); if(pd->nackcount > 20) pd->bCancel = 2; LastError(i); } return(pd->pcstate = IDX_NOCHAR); } if((mn->comstat.cbInQue >= 1) && (pd->xcount == 0)) { if(pd->bbegin && pd->bbegin != 99) { pd->bbegin = 0; pd->xwaittime = GetTickCount()+2000; } (*pd->ReadCommW) ( (HANDLE)mn->hCid,(LPSTR)pd->cbuff,(int)1); if(pd->cbuff[0] == 1) { pd->rec_len = 128; pd->xcount = 128+3; } else if(pd->cbuff[0] == EOT) pd->pcstate = IDX_EOT; else if(pd->cbuff[0] == CANCEL) { StatusLine(IDS_LASTERROR+12,NULL); (*pd->EndXfer) (); return(0); } else { i = 10; goto error_state; } pd->crc = 0; mn->comstat.cbInQue -=1; pd->rcnt = 0; } if(mn->comstat.cbInQue && pd->xcount ) { for(i=0; i<(int)mn->comstat.cbInQue; i++ ) { (*pd->ReadCommW) ( (HANDLE)mn->hCid,(LPSTR)(pd->cbuff+pd->rcnt+1),(int)1); if(++pd->rcnt<3) continue; else if( pd->rcnt < pd->xcount ) pd->crc += pd->cbuff[pd->rcnt]; if(pd->rcnt != pd->xcount) continue; if((BYTE)*(pd->cbuff+pd->xcount)==LOBYTE(pd->crc)) pd->pcstate = IDX_ACK; else { i=2; goto error_state; } } } } return(pd->pcstate); } BOOL MoreCharacters() { (*pd->GetCommErrorW) ((HANDLE)mn->hCid); if( mn->comstat.cbInQue != 0) { (*pd->FlushCommW) ( (HANDLE)mn->hCid,(int)1); return(FALSE); } else return(TRUE); } void ymodem_tx() { int nbytes; LPSTR lptr; int i; LastError(0); go_again: if(pd->rec_no == pd->end_record ) // we are at end of file we transmitt a EOT! wait for it to be acked { if(pd->bpos) { (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x4",(int)1); // send EOF and be ready to re-tx if nack pd->xcount = 1; *pd->cbuff = '\x4'; pd->pcstate = IDX_WAITACK; pd->bpos = 0; return; } else { StatusLine(IDS_LASTERROR+14,pd->szRcvFile); // Completed Xfer (*pd->EndXfer)(); return; } } if( pd->bigptr == (pd->bigbuff+10240) ) { nbytes = _lread( pd->hCommFile, pd->bigbuff, 10240); if(!nbytes) { pd->end_record = pd->rec_no = pd->bpos = 1; // this is to let the if statements pass through */ goto go_again; } pd->bigptr = pd->bigbuff; if(nbytes != 10240) { pd->end_record = pd->rec_no+(int)(nbytes/pd->rec_len); if(nbytes%pd->rec_len) pd->end_record += 1; lptr= pd->bigbuff+nbytes; for(i=0;i< (int)(10240L-nbytes);i++) *lptr++ = 0; pd->bpos = 1; } else pd->end_record = pd->rec_no - 5; } StartXRecord(pd->rec_len, pd->bigptr); pd->bigptr += pd->rec_len; if(pd->hDlg1) { pd->runcnt += pd->rec_len; wsprintf( szBuffer,"%lu",pd->runcnt); SetDlgItemText(pd->hDlg1,ID_BLKNO, szBuffer); InvalidateRect(GetDlgItem(pd->hDlg1,ID_PERCENT),NULL,FALSE); (*pd->TimeToGo) (); } pd->pcstate = IDX_WAITACK; } BOOL FileRxTX(int send, LPSTR ptr) { OFSTRUCT ofs; lstrcpy(szBuffer,pd->szTempDir); lstrcat(szBuffer,"\\"); lstrcat((LPSTR)szBuffer,ptr); lstrcpy((LPSTR)pd->szRcvFile,ptr); if(send==0) { if( (pd->hCommFile = OpenFile( (LPSTR)szBuffer, &ofs, OF_CREATE | OF_WRITE )) == -1) { StatusLine( IDS_LASTERROR+26,szBuffer); *pd->aspfxfer=ASP_PROT_FAIL; return( FALSE); } return(TRUE); } if( (pd->hCommFile = OpenFile( (LPSTR)szBuffer, &ofs, OF_READ )) == -1) { StatusLine( IDS_LASTERROR+24,szBuffer); *pd->aspfxfer=ASP_PROT_FAIL; return( FALSE); } pd->flen = filelength(pd->hCommFile); pd->fdate = getfdate(pd->hCommFile); pd->fftime = getftime(pd->hCommFile); return(TRUE); }